﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Drawing;

namespace DSA___semestralkaA___2
{
    public class Graf<T, E> : IGraf<T, E>, IEnumerable<T>
    {

        private KDStrom<IKlic> strom = new KDStrom<IKlic>();

        //přidání uzlu do grafu -> do stromu
        public bool pridejUzelDoGrafu(T uzel)
        {
            strom.pridejDoStromu(new UzelVGrafu(uzel));
            //Console.WriteLine("Uzel do stromu byl přidán (x: " + ((IKlic)uzel).getX() + " | y: " + ((IKlic)uzel).getY() + ") - sekundární klíč: " + ((IKlic)uzel).getName());
            return true;
        }

        public void zrusGraf()
        {
            strom.zrusStrom();
        }

        //vrátí nalezený uzel
        public UzelVGrafu najdiUzel(IKlic hledany)
        {
            UzelVGrafu uzel = ((UzelVGrafu)(strom.najdiVeStrome(hledany)));

            if (uzel != null)
            {
                return uzel;
            }
            else
            {
                return null;
            }
        }




        //vložím dva IKlíče (x,y) a k nim ještě vlastnosti hrany -> cena
        public bool pridejHranuDoGrafu(IKlic start, IKlic konec, E hrana)
        {
            UzelVGrafu uzelA = najdiUzel(start);
            UzelVGrafu uzelB = najdiUzel(konec);

            if (uzelA != null && uzelB != null)
            {
                //tady chci použít exists
                if (uzelA.ListHran().Contains(hrana) || uzelB.ListHran().Contains(hrana))
                {

                    //Console.WriteLine("Hrana již existuje");
                }
                else if (((IKlic)uzelA).getX() == ((IKlic)uzelB).getX() && ((IKlic)uzelA).getY() == ((IKlic)uzelB).getY())
                {
                    //Console.WriteLine("Nelze udělat hranu do stejného uzlu: A:(" + ((IKlic)uzelA).getX() + " | " + ((IKlic)uzelB).getX() + ") B:(" + ((IKlic)uzelA).getY() + " | " + ((IKlic)uzelB).getY() + ")");
                }
                else
                {
                    uzelA.ListHran().Add(hrana);
                    uzelB.ListHran().Add(hrana);
                    //Console.WriteLine("Hrana byla přidána mezi uzly: " + uzelA.getName() + " - " + uzelB.getName());
                    return true;
                }
            }
            else
            {
                //Console.WriteLine("Hrana nelze přidat");
            }
            return false;
        }

        public bool pridejHranuDoGrafuIMPORT(IKlic start, IKlic konec, E hrana)
        {
            UzelVGrafu uzelA = najdiUzel(start);
            UzelVGrafu uzelB = najdiUzel(konec);

            if (uzelA != null && uzelB != null)
            {

                uzelA.ListHran().Add(hrana);
                return true;

            }
            else
            {
                //Console.WriteLine("Hrana nelze přidat");
            }
            return false;
        }

        //odebírání hrany - pouze se všemi argumenty
        public bool odeberHranuZGrafu(IKlic start, IKlic konec, E hrana)
        {
            najdiUzel(start).ListHran().Remove(hrana);
            najdiUzel(konec).ListHran().Remove(hrana);
            //Console.WriteLine("Hrana byla odebrána");
            return true;
        }


        /// <summary>
        /// vrátí všechny hrany incidující se zadaným uzlem
        /// </summary>
        /// <param name="uzel"></param>
        /// <returns></returns>
        public List<E> vratSeznamHranVUzlu(IKlic uzel)
        {
            return najdiUzel(uzel).ListHran();
        }

        public ArrayList vratVsechnyHranyZeVsechUzlu()
        {
            ArrayList list = new ArrayList();
            foreach (UzelVGrafu uzel in strom)
            {
                foreach (var hrana in vratSeznamHranVUzlu(uzel))
                {
                    list.Add(hrana);
                }
            }

            return list;
        }

        public ArrayList vratVsechnyUzly()
        {
            ArrayList list = new ArrayList();
            foreach (UzelVGrafu uzel in strom)
            {            
                    list.Add(uzel);
            }

            return list;
        }

        public T najdiUzelPodleXY(int x, int y)
        {
            foreach (UzelVGrafu uzel in strom)
            {
                if (uzel.getX() == x && uzel.getY() == y)
                {
                    return uzel.Data;
                }
            }
            return default(T);
        }


        public Dictionary<T, int> intervaloveVyhledavani(T prvni, T druhy, T bod, int radius)
        { 

            radius = (radius/2);
            Dictionary<T, int> list = new Dictionary<T, int>();
            
            double xx;
            double yy;

            foreach (UzelVGrafu item in strom.intervaloveVyhledavaniCtverec((IKlic)prvni, (IKlic)druhy))
	        {
                //vypočítat euklidovskou vzádlenost
                xx = Math.Pow((item.getX() - (((IKlic)bod).getX())), 2);
                yy = Math.Pow((item.getY() - ((IKlic)bod).getY()), 2);

                double tmp = Math.Sqrt((xx + yy));
                if (tmp < radius)
                {
                    list.Add(item.Data, (int)tmp);
                }
	        }

            //foreach (UzelVGrafu item in strom.intervaloveVyhledavaniCtverec((IKlic)prvni, (IKlic)druhy))
            //{
            //    list.Add(item.Data, 1);
            //}


            return list;
            
        }







        //public void testVratJednuHranu(IKlic start, IKlic konec)
        //{
        //    List<E> seznamHranA = najdiUzel(start).ListHran();

        //    foreach (var item in seznamHranA)
        //    {
        //        //if ((IKlic)item == konec)
        //        //{ 
        //        //    Console.WriteLine("našel jsem uzel");
        //        //}
        //    }
        //}




        //implementace enumerátoru
        public IEnumerator<T> GetEnumerator()
        {
            foreach (UzelVGrafu item in strom)
            {
                yield return item.Data;
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<T>)this).GetEnumerator();
        }



        /// <summary>
        /// Třída, která se stará o reprezentaci uzlu v grafu - implementuje rozhraní IKlic
        /// Každý uzel si v sobě uchovává seznam incidentních hran
        /// Data se propadají do KDstromu
        /// </summary>
        public class UzelVGrafu : IKlic, IEnumerable
        {
            private T data;
            List<E> listHran = new List<E>();

            public UzelVGrafu(T data)
            {
                this.Data = data;
            }

            public T Data
            {
                get { return data; }
                set { data = value; }
            }

            public List<E> ListHran()
            {
                return listHran;
            }


            public int getX()
            {
                return ((IKlic)Data).getX();
            }

            public int getY()
            {
                return ((IKlic)Data).getY();
            }

            public string getName()
            {
                return ((IKlic)Data).getName();
            }

            public IEnumerator GetEnumerator()
            {
                foreach (E item in listHran)
                {
                    yield return item;
                }
            }
        }



    }


}
